package com.zhaopin.utils;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.*;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;

import java.io.File;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Iterator;

@Slf4j
public class GitUtils {

    static {
        CredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider("yin.peide@zhaopin.com.cn","a1472589630");
        CredentialsProvider.setDefault(credentialsProvider);
    }

    public static void main(String[] args) throws IOException {

    }


    /**
     * 强推本地同步到线上
     * @param repoDir
     * @return
     * @throws IOException
     */
    public static boolean forceUpdateHeadToRemote(File repoDir) throws IOException {
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            log.debug("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                git.push().setForce(true).call();
                return true;
            } catch (Exception e) {
                log.debug(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }

        }
        return false;
    }


    public static boolean rollBackOneRevision(File repoDir, String revision) throws IOException {
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            log.debug("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                git.reset().setMode(ResetCommand.ResetType.HARD).setRef(revision).call();
                return true;
            } catch (Exception e) {
                log.debug(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }

        }
        return false;
    }
    /**
     * 将git仓库内容回滚到指定版本的上一个版本
     * @param repoDir 仓库目录文件
     * @param revision 指定的版本号
     * @return true,回滚成功,否则flase
     * @throws IOException
     */
    public static boolean rollBackPreRevision(File repoDir, String revision) throws IOException {
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            log.debug("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                RevWalk walk = new RevWalk(repo);
                ObjectId objId = repo.resolve(revision);
                RevCommit revCommit = walk.parseCommit(objId);
                String preVision = revCommit.getParent(0).getName();
                git.reset().setMode(ResetCommand.ResetType.HARD).setRef(preVision).call();
                return true;

            } catch (Exception e) {
                log.debug(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }

        }
        return false;
    }

    //获取上一个版本的对象
    public static RevCommit getNextVersionLog(File repoDir) {
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            log.debug("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                ObjectId head = repo.resolve(Constants.HEAD);
                Iterable<RevCommit> call = git.log().add(head).setMaxCount(10).call();
                Iterator<RevCommit> iterator = call.iterator();
                boolean getUpperVersion = false;
                while (iterator.hasNext()){
                    RevCommit revCommit = iterator.next();
                    if(!getUpperVersion && revCommit.getFullMessage().contains("similarJobLevelForCV_Exp5")){
                        System.out.println(revCommit);
                        getUpperVersion = true;
                        break;
                    }
                }
                return iterator.next();
            } catch (Exception e) {
                log.debug(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }

        }
        return null;
    }

    /**
     * 修改 提交 设置tag 同步远端一条龙
     * @param repoDir
     * @param message
     * @param prefix
     * @param updateTag
     */
    public static void gitAllDo(File repoDir,String message,String prefix,boolean updateTag) {
        if(prefix == null){
            prefix = "release-v0.0.1-";
        }
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            System.out.println("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                git.add().addFilepattern(".").setUpdate(true).call();
                RevCommit commitCall = git.commit().setMessage(message).setAuthor("yin.peide", "yin.peide@zhaopin.com.cn").call();
                //TODO  此处可以加上如果未提交成功则不打 tag
                git.tag().setName(prefix + DateTimeFormatter.ofPattern("yyyyMMddHHmm").format(LocalDateTime.now())).call();
                //是否同步tag到服务端
                if(updateTag){
                    git.push().setPushTags().setPushAll().call();
                }else{
                    git.push().setPushAll().call();
                }

                System.out.println("add commit tag push  from remote repository to local repository at " + repo.getDirectory());
            } catch (Exception e) {
                System.out.println(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }
        }
    }



    /**
     * 拉取
     * @param repoDir
     */
    public static void gitPull(File repoDir) {
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            System.out.println("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                PullCommand pullCmd = git.pull();
                pullCmd.call();

                System.out.println("Pulled from remote repository to local repository at " + repo.getDirectory());
            } catch (Exception e) {
                System.out.println(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }
        }
    }


    /**
     * 添加
     * @param repoDir
     */
    public static void getAdd(File repoDir) {
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            System.out.println("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                AddCommand add = git.add().addFilepattern(repoDir.getAbsolutePath());
                add.call();
                System.out.println("Added from remote repository to local repository at " + repo.getDirectory());
            } catch (Exception e) {
                System.out.println(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }
        }
    }


    /**
     * 提交
     * @param repoDir
     */
    public static void getCommit(File repoDir,String message) {
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            System.out.println("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                CommitCommand commit = git.commit();
                commit.setMessage(message).setAuthor("yin.peide","yin.peide@zhaopin.com.cn").call();
                System.out.println("Commited from remote repository to local repository at " + repo.getDirectory());
            } catch (Exception e) {
                System.out.println(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }
        }
    }


    /**
     * 推送到远端
     * @param repoDir
     */
    public static void getPush(File repoDir) {
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            System.out.println("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                PushCommand push = git.push();
                push.call();

                System.out.println("Pushed from remote repository to local repository at " + repo.getDirectory());
            } catch (Exception e) {
                System.out.println(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }
        }
    }

    public static void getPushWithTag(File repoDir,String prefix,boolean updateTag) {
        if(prefix == null){
            prefix = "release-v0.0.1-";
        }
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            System.out.println("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                git.tag().setName(prefix + DateTimeFormatter.ofPattern("yyyyMMddHHmm").format(LocalDateTime.now())).call();
                //是否同步tag到服务端
                if(updateTag){
                    git.push().setPushTags().setPushAll().call();
                }else{
                    git.push().setPushAll().call();
                }

                System.out.println("Pushed from remote repository to local repository at " + repo.getDirectory());
            } catch (Exception e) {
                System.out.println(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }
        }
    }

    /**
     * 本地打 tag
     * @param repoDir
     */
    public static void getTag(File repoDir,String prefix) {
        if(prefix == null){
            prefix = "release-v0.0.1";
        }
        File RepoGitDir = new File(repoDir.getAbsolutePath() + "/.git");
        if (!RepoGitDir.exists()) {
            System.out.println("Error! Not Exists : " + RepoGitDir.getAbsolutePath());
        } else {
            Repository repo = null;
            try {
                repo = new FileRepository(RepoGitDir.getAbsolutePath());
                Git git = new Git(repo);
                TagCommand tag = git.tag();
                tag.setName(prefix + DateTimeFormatter.ofPattern("MMddHHmm").format(LocalDateTime.now()));
                tag.call();

                System.out.println("Taged from remote repository to local repository at " + repo.getDirectory());
            } catch (Exception e) {
                System.out.println(e.getMessage() + " : " + RepoGitDir.getAbsolutePath());
            } finally {
                if (repo != null) {
                    repo.close();
                }
            }
        }
    }


}
